package com.xishu.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.xishu.bo.ImageText;
import com.xishu.bo.image.ImageSize;
import com.xishu.config.Config;
import com.xishu.exception.ResponseStatusException;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

public class ImgUtil implements Tools {
    private static Logger logger = LoggerFactory.getLogger(ImgUtil.class);
    public static final String FONT_FILE_LOCATION = "/usr/share/fonts/zh/simsun.ttf";

    private static final int BLACK = 0xFF000000;

    private static final int WHITE = 0xFFFFFFFF;

    public static void compress(File file, File outFile, double scale) throws IOException {
        try {
            Thumbnails.of(file)
                    .scale(scale)
                    .outputFormat("jpg")
                    .toFile(outFile);
        } catch (Exception e) {
            logger.error("-----try cmyk format-----", e);
            File cmykJPEGFile = new File(file.getAbsolutePath());
            try {
                BufferedImage image = ImageIO.read(cmykJPEGFile);
                ImageOutputStream output = ImageIO.createImageOutputStream(cmykJPEGFile);
                if (!ImageIO.write(image, "jpg", output)) {
                    logger.info("-----cmyk format error :{}-----");
                }
                Thumbnails.of(image).scale(scale).toFile(outFile);
                logger.debug("-----cmyk转化成功-----");
            } catch (IOException e1) {
                logger.error("-----cmyk format error-----", e1.getMessage());
            }
        }
    }

    /**
     * 将文件压缩成固定大小
     *
     * @param file
     * @param targetSize
     * @throws IOException
     */
    public static File compressSize(File file, double targetSize) throws IOException, ResponseStatusException {
        logger.info("src file size {}, target size {}, scale is {}", file.length(), targetSize, targetSize / file.length());

        if (file.length() > targetSize) {

            double scale = targetSize / file.length();
            String suffix = FileUtil.getSuffix(file.getName());
            File outFile = MongoId.getInstance().generateTmpFile(suffix);

            //压缩
            compress(file, outFile, scale);

            return outFile;
        } else {
            return file;
        }
    }

    /**
     * 产生图片
     *
     * @param content
     * @return
     */
    public static File generateImageFile(String content, ImageSize imageSize) throws Exception {
        //得到图片缓冲区
        BufferedImage bi = new BufferedImage(imageSize.getWidth(), imageSize.getHeight(), BufferedImage.TYPE_INT_RGB);//INT精确度达到一定,RGB三原色，高度70,宽度150

        //得到它的绘制环境(这张图片的笔)
        Graphics2D g2 = (Graphics2D) bi.getGraphics();

        g2.fillRect(0, 0, imageSize.getWidth(), imageSize.getHeight());
        //填充一个矩形 左上角坐标(0,0),宽70,高150;填充整张图片
        //设置颜色
        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, imageSize.getWidth(), imageSize.getHeight());//填充整张图片(其实就是设置背景颜色)

//        g2.setColor(Color.RED);
//        g2.drawRect(0, 0, 150 - 1, 70 - 1); //画边框

        g2.setFont(new Font("宋体", Font.BOLD, 18)); //设置字体:字体、字号、大小
        g2.setColor(Color.BLACK);//设置背景颜色

        g2.drawString(content, 0, imageSize.getHeight() / 2); //向图片上写字符串
        File tmpFile = MongoId.getInstance().generateTmpFile("jpg");
        logger.info("tmp file is {}", tmpFile.getAbsolutePath());
        ImageIO.write(bi, "JPEG", tmpFile);//保存图片 JPEG表示保存格式
        return tmpFile;
    }

    /**
     * 获取文件长宽
     *
     * @param file
     * @return
     */
    public static ImageSize getImgSize(File file) throws Exception {
        File generateTmpFile = MongoId.getInstance().generateTmpFile("txt");
        CmdUtil.executeShellCmd(String.format("convert %s  -print \"%%wx%%h\" /dev/null > %s", file.getAbsolutePath(), generateTmpFile.getAbsolutePath()));
        //读取文件
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(generateTmpFile), "UTF-8"));//构造一个BufferedReader类来读取文件
        try {
            String size = br.readLine();
            String[] split = size.split("x");
            return new ImageSize(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
        } finally {
            IOUtils.closeQuietly(br);
        }
    }

    /**
     * 产生图片
     *
     * @return
     */
    public static File generateImageFile(ImageSize imageSize, Color backColor, Color borderColor) throws Exception {
        //得到图片缓冲区
        BufferedImage bi = new BufferedImage(imageSize.getWidth(), imageSize.getHeight(), BufferedImage.TYPE_INT_RGB);//INT精确度达到一定,RGB三原色，高度70,宽度150

        //得到它的绘制环境(这张图片的笔)
        Graphics2D g2 = (Graphics2D) bi.getGraphics();

        g2.fillRect(0, 0, imageSize.getWidth(), imageSize.getHeight());
        //填充一个矩形 左上角坐标(0,0),宽70,高150;填充整张图片
        //设置颜色
        g2.setColor(backColor);
        g2.fillRect(0, 0, imageSize.getWidth(), imageSize.getHeight());//填充整张图片(其实就是设置背景颜色)

        if (borderColor != null) {
            g2.setColor(borderColor);
            g2.drawRect(0, 0, imageSize.getWidth() - 1, imageSize.getHeight() - 1); //画边框
        }

        g2.setFont(new Font("宋体", Font.BOLD, 18)); //设置字体:字体、字号、大小
        g2.setColor(Color.BLACK);//设置背景颜色

        File tmpFile = MongoId.getInstance().generateTmpFile("jpg");
        logger.info("tmp file is {}", tmpFile.getAbsolutePath());
        ImageIO.write(bi, "JPEG", tmpFile);//保存图片 JPEG表示保存格式
        return tmpFile;
    }


    //根据文字生成图片
    //convert  -font simsun.ttc  -fill white  -pointsize 36 -draw  'text 50,50 "優惠券"' new.jpg test.jpg

    //convert background.jpg -compose over front.jpg  -composite new.jpg
    //$convert image.png -gravity NorthEast -geometry +10+10  -compose over overlay.png -composite newimage.png
    //-gravity 表示合并的位置方向
    // geometry 合并的起始位置

    //使用linux中的convert命令修改图片大小
    //convert -resize 22x22! Valuair.png val.png
    //    #横向拼接
    //    convert 1.jpg 2.jpg 3.jpg +append result.jpg
    //
    //#纵向拼接
    //    convert 1.jpg 2.jpg 3.jpg -append result.jpg

    //#把图片合并成 PDF
    //convert 1.jpg 2.jpg +compress res.pdf

    //添加边框
    //convert exam.jpg -bordercolor blue -border 5 border-1.jpg

    /**
     * 向图片的指定位置写文本
     *
     * @param file
     * @param imageText
     * @return
     */
    public static File writeText(File file, ImageText imageText) {
        try {
            logger.info("write text {} to file", imageText.getContent());
            // convert  -font simsun.ttc  -fill white  -pointsize 36 -draw  'text 50,50 "優惠券"' new.jpg test.jpg
            String color = imageText.getColor();

            if (color == null) {
                color = "black";
            }

            File tmpFile = MongoId.getInstance().generateTmpFile("jpg");

            String cmd = String.format("convert -font %s -fill %s -pointsize %s -draw  'text %s,%s \"%s\"' %s %s",
                    FONT_FILE_LOCATION, color, imageText.getSize(), imageText.getX(), imageText.getY(), imageText.getContent(), file.getAbsolutePath(), tmpFile.getAbsolutePath());

            logger.info("cmd is {}", cmd);
            CmdUtil.executeShellCmd(cmd);
            return tmpFile;
        } catch (Exception e) {
            logger.error("e", e);
            return null;
        }
    }

    /**
     * 将文件放在哪一个位置上面，并且设置大小
     *
     * @param backEndFile
     * @param frontEndFile
     * @return
     */
    public static File imageOver(File backEndFile, File frontEndFile, ImageSize imageSize, String location) throws Exception {
        File tmpFile = MongoId.getInstance().generateTmpFile("jpg");
        CmdUtil.executeShellCmd(String.format("convert %s -gravity %s  -compose over %s -composite %s", backEndFile.getAbsolutePath(), location, frontEndFile.getAbsolutePath(), tmpFile.getAbsolutePath()));
        return tmpFile;
    }

    /**
     * 合并文件,上下两个文件合并
     *
     * @param topFile  上面的一个文件
     * @param downFile 下面的一个文件
     * @return
     */
    public static File combineFileUD(File topFile, File downFile) throws Exception {
        if (topFile == null) {
            logger.info("file1 is null");
            return downFile;
        }

        if (downFile == null) {
            logger.info("file2 is null");
            return topFile;
        }

        File destFile = MongoId.getInstance().generateTmpFile(FileUtil.JPG);
        CmdUtil.executeShellCmd(String.format("convert -append %s %s %s", topFile.getAbsolutePath(), downFile.getAbsolutePath(), destFile.getAbsolutePath()));
        return destFile;
    }

    /**
     * 左右两个文件合并
     *
     * @param leftFile  左边个文件
     * @param rightFile 右边个文件
     * @return
     */
    public static File combineFileLR(File leftFile, File rightFile) throws Exception {
        if (leftFile == null) {
            logger.info("left file is empty");
            return rightFile;
        }

        if (rightFile == null) {
            logger.info("right file is empty");
            return leftFile;
        }

        File destFile = MongoId.getInstance().generateTmpFile(FileUtil.JPG);
        CmdUtil.executeShellCmd(String.format("convert +append %s %s %s", leftFile.getAbsolutePath(), rightFile.getAbsolutePath(), destFile.getAbsolutePath()));
        return destFile;
    }

    /**
     * 将图片强制转换成指定大小
     *
     * @param srcFile
     * @param imageSize
     * @return
     */
    public static File resize(File srcFile, ImageSize imageSize) throws Exception {
        if (srcFile == null) {
            logger.info("src file is null");
            return null;
        }

        File desFile = MongoId.getInstance().generateTmpFile("jpg");
        CmdUtil.executeShellCmd(String.format("convert -resize %sx%s! %s %s", imageSize.getWidth(), imageSize.getHeight(), srcFile.getAbsolutePath(), desFile.getAbsolutePath()));
        return desFile;
    }

    /**
     * 给图片添加边框
     *
     * @param srcFile
     * @param color
     * @param size
     * @return
     */
    public static File addBorder(File srcFile, String color, String size) throws Exception {
        if (srcFile == null) {
            logger.info("src file is null");
            return null;
        }

        File desFile = MongoId.getInstance().generateTmpFile("jpg");
        CmdUtil.executeShellCmd(String.format("convert %s -bordercolor %s -border %s %s", srcFile.getAbsolutePath(), color, size, desFile.getAbsolutePath()));
        return desFile;
    }

    /**
     * 生成图片缓存
     *
     * @param matrix
     * @return
     */
    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    /**
     * 生成文件
     *
     * @param matrix
     * @param format
     * @param file
     * @throws IOException
     */
    public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }


    /**
     * 产生二维码文件图片
     *
     * @param qrCode
     * @return
     */
    public static File createQrCode(String qrCode) {
        try {
            Map<EncodeHintType, String> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = new MultiFormatWriter().encode(qrCode, BarcodeFormat.QR_CODE, 400, 400, hints);

            Config config = Config.getInstance();
            File file = new File(config.getUploadTmpPath(), qrCode + ".png");

            if (file.createNewFile()) {
                writeToFile(bitMatrix, "jpg", file);
                logger.info("generate qr pay file {}", file.getAbsolutePath());
            }

            return file;

        } catch (Exception e) {
            logger.error("e", e);
        }

        return null;
    }

    public static void main(String[] args) throws Exception {
//        generateImageFile("hello xishu !", new ImageSize(150, 70));
//        generateImageFile(new ImageSize(560, 560), Color.WHITE, Color.BLACK);
        generateImageFile(new ImageSize(100, 100), new Color(87, 188, 184), Color.WHITE);
    }


}
